#include "NeoScrollBar.h"
#include "private/NeoScrollBarPrivate.h"
#include "style/NeoScrollBarStyle.h"
#include <QAbstractScrollArea>
#include <QEvent>
#include <QPropertyAnimation>
#include <QWheelEvent>

NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoScrollBar, int, Extent)
NEO_PUBLIC_PROPERTY_CREATE_CPP(NeoScrollBar, int, WheelSpeed)

NeoScrollBar::NeoScrollBar(QWidget *parent)
    : QScrollBar(parent), d_ptr(new NeoScrollBarPrivate())
{
    NEO_PUBLIC_POINT(NeoScrollBar)
    d->q_ptr = this;
    d->pPositionAnimation->setTargetObject(this);
    d->pPositionAnimation->setPropertyName("value");
    this->setStyle(new NeoScrollBarStyle(this->style()));
    // This property is set to false to allow the background to be painted correctly.
    this->setAttribute(Qt::WA_OpaquePaintEvent, false);
}

NeoScrollBar::NeoScrollBar(Qt::Orientation orientation, QWidget *parent)
    : NeoScrollBar(parent)
{
    this->setOrientation(orientation);
}

NeoScrollBar::NeoScrollBar(QAbstractScrollArea *parent, Qt::Orientation orientation)
    : NeoScrollBar(orientation, parent)
{
    parent->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    parent->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    QScrollBar *scrollBar = orientation == Qt::Horizontal ? parent->horizontalScrollBar() : parent->verticalScrollBar();
    parent->viewport()->installEventFilter(this);
    connect(scrollBar, &QScrollBar::rangeChanged, this, &NeoScrollBar::setRange);
    connect(this, &NeoScrollBar::valueChanged, scrollBar, &QScrollBar::setValue);
    connect(scrollBar, &QScrollBar::valueChanged, this, &NeoScrollBar::setValue);
}

NeoScrollBar::~NeoScrollBar() = default;

void NeoScrollBar::setScrollSpeed(int speed)
{
    NEO_PUBLIC_POINT(NeoScrollBar)
    d->pScrollSpeed = speed;
    d->pPositionAnimation->setDuration(speed * 100);
}

int NeoScrollBar::getScrollSpeed() const
{
    NEO_PUBLIC_POINT(const NeoScrollBar)
    return d->pScrollSpeed;
}

void NeoScrollBar::setAnimationValue(int value)
{
    NEO_PUBLIC_POINT(NeoScrollBar)
    d->setAnimationValue(value);
}

bool NeoScrollBar::eventFilter(QObject *watched, QEvent *event)
{
    switch (event->type())
    {
    case QEvent::Resize:
    case QEvent::Show:
    {
        NEO_PUBLIC_POINT(NeoScrollBar)
        d->updateWidgetGeometry();
        break;
    }
    case QEvent::Wheel:
    {
        NEO_PUBLIC_POINT(NeoScrollBar)
        QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
        d->setAnimationValue(this->value() - this->pageStep() * d->pWheelSpeed * wheelEvent->angleDelta().y() / 120);
        return true;
    }
    default:
        break;
    }
    return QScrollBar::eventFilter(watched, event);
}